package com.cyc.common.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

/**
 * 日期工具 jdk8
 *
 * @description:
 * @author: liudh
 * @time: 2020/7/17
 */
public final class DateUtil {

    //数据库格式的日期
    public static final String SQL_MONTH = "yyyy-MM";
    public static final String SQL_DATE = "yyyy-MM-dd";
    public static final String SQL_DATE_TIME = "yyyy-MM-dd HH:mm";
    public static final String SQL_TIME = "yyyy-MM-dd HH:mm:ss";
    public static final String SQL_TIMESTAMP = "yyyy-MM-dd HH:mm:ss.SS";

    //斜杠格式的日期
    public static final String DATE = "yyyy/MM/dd";
    public static final String TIMESTAMP = "yyyy/MM/dd HH:mm:ss.SS";
    public static final String TIMESTAMP_SHORT = "yyyy/MM/dd HH:mm";
    public static final String TIME = "HH:mm:ss";
    public static final String TIME_SHORT = "HH:mm";

    //不常用日期格式
    public static final String CHINESEDATE = "yyyy年MM月dd日";
    public static final String DATE_TIME = "yyyyMMddHHmmss";
    public static final String DATE_TIME_DETAIL = "yyyyMMddHHmmssSS";
    public static final String DATE_DAY = "yyyyMMdd";
    public static final String DATE_HOUR = "yyyyMMddHH";
    public static final String HOUR_DATE = "HH-mm-MMdd";


    /**
     * 防止被实例化
     */
    private DateUtil() {

    }

    /**
     * Date转LocalDateTime
     * 使用系统时区
     *
     * @param date 是打发斯蒂芬
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDateTime转Date
     * 使用系统时区
     *
     * @param localDateTime
     * @return
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }

    /**
     * 日期转字符串
     *
     * @param localDateTime
     * @param pattern
     * @return
     */
    public static String dateTimeToStr(LocalDateTime localDateTime, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return localDateTime.format(formatter);
    }

    /**
     * 将字符串日期解析为java.time.LocalDateTime
     *
     * @param dateTimeStr
     * @param pattern
     * @return
     */
    public static LocalDateTime strToLocalDateTime(String dateTimeStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(dateTimeStr, formatter);
    }

    public static LocalDate strToLocalDate(String dateTimeStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(dateTimeStr, formatter);
    }

    /**
     * 开始日期，补齐" 00:00:00"
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getStartDateTimeWithHMS(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
    }

    /**
     * 结束日期，补齐" 23:59:59"
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getEndDateWithHMS(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
    }

    /**
     * 字符串类型补全开始时期
     *
     * @param dateTimeStr yy-MM-dd格式日期
     * @return
     */
    public static LocalDateTime getStartDateWithHMS(String dateTimeStr) {
        dateTimeStr += " 00:00:00";
        LocalDateTime localDateTime = strToLocalDateTime(dateTimeStr, SQL_TIME);
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
    }

    /**
     * 字符串类型补全结束时期
     *
     * @param dateTimeStr yy-MM-dd格式日期
     * @return
     */
    public static LocalDateTime getEndDateWithHMS(String dateTimeStr) {
        dateTimeStr += " 00:00:00";
        LocalDateTime localDateTime = strToLocalDateTime(dateTimeStr, SQL_TIME);
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
    }


    public static LocalDateTime getAfterYears(LocalDateTime localDateTime, int count) {
        return localDateTime.plusYears(count);
    }

    public static LocalDateTime getAfterMonths(LocalDateTime localDateTime, int count) {
        return localDateTime.plusMonths(count);
    }

    public static LocalDateTime getAfterDays(LocalDateTime localDateTime, int count) {
        return localDateTime.plusDays(count);
    }

    public static LocalDate getAfterDays(LocalDate localDate, int count) {
        return localDate.plusDays(count);
    }

    public static LocalDateTime getAfterMinutes(LocalDateTime localDateTime, int count) {
        return localDateTime.plusMinutes(count);
    }

    public static LocalDateTime getAfterSeconds(LocalDateTime localDateTime, int count) {
        return localDateTime.plusSeconds(count);
    }


    /**
     * 获得当前年的第一天
     *
     * @param
     * @return
     */
    public static LocalDateTime getYearFirstDay(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.firstDayOfYear());
    }

    /**
     * 获得当前年的最后一天
     *
     * @param
     * @return
     */
    public static LocalDateTime getYearLastDay(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.lastDayOfYear());
    }


    /**
     * 获得当前月的第一天
     *
     * @param
     * @return
     */
    public static LocalDateTime getMonthFirstDay(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获得当前月的最后一天
     *
     * @param
     * @return
     */
    public static LocalDateTime getMonthLastDay(LocalDateTime localDateTime) {
        return localDateTime.with(TemporalAdjusters.lastDayOfMonth());
    }


    /**
     * 获得当前星期的第一天
     *
     * @param localDateTime
     * @param locale        默认Locale.CHINA 周日为一周的第一天
     * @return
     */
    public static LocalDateTime getWeekFirstDay(LocalDateTime localDateTime, Locale locale) {
        return localDateTime.with(WeekFields.of(locale == null ? Locale.CHINA : locale).dayOfWeek(), 1);
    }

    /**
     * 获得当前星期的最后一天
     *
     * @param localDateTime
     * @param locale        默认默认Locale.CHINA 周日为一周的第一天
     * @return
     */
    public static LocalDateTime getWeekLastDay(LocalDateTime localDateTime, Locale locale) {
        return localDateTime.with(WeekFields.of(locale == null ? Locale.CHINA : locale).dayOfWeek(), 7);
    }


    /**
     * 计算两个日期之间相差年数
     *
     * @param smallDateTime 较小的时间
     * @param bigDateTime   较大的时间
     * @return 相差年数
     */
    public static int getYearDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.YEARS);
    }

    /**
     * 计算两个日期之间相差月数
     *
     * @param smallDateTime 较小的时间
     * @param bigDateTime   较大的时间
     * @return 相差月数
     */
    public static int getMonthDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.MONTHS);
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param smallDateTime 较小的时间
     * @param bigDateTime   较大的时间
     * @return 相差天数
     */
    public static int getDayDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.DAYS);
    }


    public static int getDayDiff(String smallDateTime, String bigDateTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return DateUtil.getDayDiff(LocalDateTime.parse(smallDateTime, df),
                LocalDateTime.parse(bigDateTime, df));
    }

    /**
     * 计算两个日期之间相差小时数
     *
     * @param smallDateTime 较小的时间
     * @param bigDateTime   较大的时间
     * @return 相差小时数
     */
    public static int getHourDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.HOURS);
    }

    /**
     * 计算两个日期之间相差分钟数
     *
     * @param smallDateTime
     * @param bigDateTime
     * @return 相差分钟数
     */
    public static int getMinutesDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.MINUTES);
    }

    /**
     * 计算两个日期之间相差秒数
     *
     * @param smallDateTime
     * @param bigDateTime
     * @return 相差秒数
     */
    public static int getSecondsDiff(LocalDateTime smallDateTime, LocalDateTime bigDateTime) {
        return (int) smallDateTime.until(bigDateTime, ChronoUnit.SECONDS);
    }

    /**
     * 获取当前时间与第二天00点相差多少秒
     *
     * @return
     */
    public static int getSecondsDiffForNow() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime today_start = LocalDateTime.of(LocalDate.now().plusDays(1), LocalTime.MIN);
        int secondsDiff = getSecondsDiff(now, today_start);
        return secondsDiff;
    }

    /**
     * @param start 开始时间 格式yyyy-mm-dd
     * @param end   结束时间 格式yyyy-mm-dd
     * @return list<string>期间的所有日期
     */
    public static List<String> compeleteDate(String start, String end, String format) {
        ArrayList<String> aList = new ArrayList<String>();
        if (start.equals(end)) {
            aList.add(start);
            return aList;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        long num = 0;
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        try {
            Date date1 = sdf.parse(start);
            Date date2 = sdf.parse(end);
            c1.setTime(date1);
            long time1 = c1.getTimeInMillis();
            c2.setTime(date2);
            long time2 = c2.getTimeInMillis();
            num = (time2 - time1) / (1000 * 3600 * 24);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (num == 0) {
            return null;
        }
        for (int i = 0; i <= num; i++) {
            aList.add(sdf.format(c1.getTime()));
            c1.add(Calendar.DAY_OF_YEAR, 1);
        }

        return aList;
    }

    /**
     * SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
     * Date dBegin = sdf.parse("2018-01-01 11:00:00");
     * Date dEnd = sdf.parse("2019-01-01 11:00:00");
     * <p>
     * 功能描述: 获取时间段内的整点小时
     *
     * @param dBegin
     * @param dEnd
     * @throws ParseException
     */
    public static List<String> findDates(Date dBegin, Date dEnd) throws ParseException {

        List<String> lDate = new ArrayList<String>();
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        lDate.add(sd.format(dBegin));
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.HOUR, 1);
            lDate.add(sd.format(calBegin.getTime()));
        }
        return lDate;
    }

    /**
     * @param start 开始时间 格式yyyy-mm-dd
     * @param end   结束时间 格式yyyy-mm-dd
     * @return list<string>期间的所有日期时分
     */
    public static List<String> compeleteDateTime(String start, String end, String format) {
        ArrayList<String> aList = new ArrayList<String>();
        if (start.equals(end)) {
            aList.add(start);
            return aList;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        int num = 0;
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        try {
            Date date1 = sdf.parse(start);
            Date date2 = sdf.parse(end);
            c1.setTime(date1);
            c2.setTime(date2);
            num = (c2.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR) + 1) * 24 - 1;
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (num == 0) {
            return null;
        }
        for (int i = 0; i <= num; i++) {
            aList.add(sdf.format(c1.getTime()));
            c1.add(Calendar.HOUR_OF_DAY, 1);
        }
        return aList;
    }


    public static Date getDateAdd(int days) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, -days);
        return c.getTime();
    }

    public static List<String> getDaysBetwwen(int days) { //最近几天日期
        List<String> dayss = new LinkedList<>();
        Calendar start = Calendar.getInstance();
        start.setTime(getDateAdd(days));
        Long startTIme = start.getTimeInMillis();
        Calendar end = Calendar.getInstance();
        end.setTime(new Date());
        Long endTime = end.getTimeInMillis();
        Long oneDay = 1000 * 60 * 60 * 24L;
        Long time = startTIme;
        while (time <= endTime) {
            Date d = new Date(time);
            DateFormat df = new SimpleDateFormat("yyyyMMdd");
            dayss.add(df.format(d));
            time += oneDay;
        }
        return dayss;
    }

    /**
     * 时间转换
     *
     * @param dataTimeList
     * @param formatterDataTiems
     */
    public static void formatterDateTiem(List<String> dataTimeList, List<String> formatterDataTiems, String dateType) {

        if (dateType.equals("DATE")) {
            dataTimeList.forEach(data -> formatterDataTiems.add(data));
        } else if (dateType.equals("HOUR")) {
            SimpleDateFormat start = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            SimpleDateFormat end = new SimpleDateFormat(" HH:mm");
            Calendar calendar = Calendar.getInstance();
            dataTimeList.forEach(data -> {
                try {
                    calendar.setTime(start.parse(data));
                    calendar.add(Calendar.HOUR, 1);
                    calendar.add(Calendar.MINUTE, -1);
                    formatterDataTiems.add(start.format(start.parse(data)) + " ~ " + end.format(calendar.getTime()));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            });
        } else if (dateType.equals("COLLECT")) {
            dataTimeList.forEach(data -> formatterDataTiems.add(data));
        }


    }

    /**
     * 秒转分钟    eg: 100秒   01:40
     *
     * @param timeTemp
     * @return
     */
    public static String secondForMinute(Object timeTemp) {
        int timeParam = 0;
        if (timeTemp instanceof Integer) {
            timeParam = (Integer) timeTemp;
        }
        if (timeTemp instanceof String) {
            timeParam = Integer.valueOf((String) timeTemp);
        }
        int second = timeParam % 60;
        int minuteTemp = timeParam / 60;
        if (minuteTemp > 0) {
            int minute = minuteTemp % 60;
            return (minute > 10 ? (minute + "") : ("0" + minute)) + ":"
                    + (second > 10 ? (second + "") : ("0" + second));
        } else {
            return "00:" + (second > 10 ? (second + "") : ("0" + second));
        }
    }


    /**
     * 获取秒
     *
     * @param second
     * @return
     */
    public static List<String> getSecond(Integer second) {
        List<String> secondDate = new ArrayList<>();
        for (int i = second; i >= 0; i--) {
            secondDate.add(i + "");
        }
        secondDate.sort((o1, o2) -> Integer.valueOf(o1) > Integer.valueOf(o2) ? 1 : -1);
        return secondDate;
    }

}
